#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
static const int default_socketfd = -1;
static const int size = 1024;
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;

class UdpSocket
{
public:
    UdpSocket()
        :_socketfd(default_socketfd)
    {}
    bool Socket()
    {
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            std::cerr << "socket error" << std::endl;
            return false;
        }
        return true;
    }
    bool Bind(const std::string ip, uint16_t port)
    {
        sockaddr_in myaddr;
        myaddr.sin_family = AF_INET;
        myaddr.sin_port = htons(port);
        inet_aton(ip.c_str(), &myaddr.sin_addr);
        if (-1 == bind(_socketfd, (sockaddr*)&myaddr, sizeof(myaddr)))
        {
            std::cerr << "bind failed" << std::endl;
            return false;
        }
        return true;
    }
    bool RecvFrom(std::string* message, std::string* ip, uint16_t* port)
    {
        char buff[size];
        sockaddr_in clientaddr;
        socklen_t addr_len = sizeof(clientaddr);
        int n = recvfrom(_socketfd, buff, sizeof(buff), 0 , (sockaddr*)&clientaddr, &addr_len);
        if (n > 0)
        {
            buff[n] = 0;
            *message = buff;
            *port = ntohs(clientaddr.sin_port);
            *ip = inet_ntoa(clientaddr.sin_addr);
            return true;
        }
        else
        {
            return false;
        }
    }
    bool SendTo(const std::string& message, const std::string& ip, uint16_t port)
    {
        sockaddr_in svraddr;
        svraddr.sin_family = AF_INET;
        svraddr.sin_port = htons(port);
        inet_aton(ip.c_str(), &svraddr.sin_addr);
        if (sendto(_socketfd, message.c_str(), message.size(), 0, (sockaddr*)&svraddr, sizeof(svraddr)) > 0)
        {
            return true;
        }
        return false;
    }
    bool Close()
    {
        close(_socketfd);
        return true;
    }
    ~UdpSocket()
    {}
private:
    int _socketfd;
};